package com.dynamic.mybatis.core.mock;

import cn.hutool.core.date.DateUtil;
import com.dynamic.mybatis.core.enums.CommandType;
import com.dynamic.mybatis.core.enums.Type;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.utils.StringUtils;

import java.util.*;
import java.util.function.Function;

/**
 * @Description
 * @Author xs
 * @Date 2023/4/19 13:14
 */
public interface Mock {
    Map<String, Mock> typeMockMap = new HashMap() {{
        for (Mock typeMock : Mock.TypeMock.values()) {
            put(typeMock.type(), typeMock);
        }
    }};

    String type();

    Function function();

    enum TypeMock implements Mock {
        // new Random().nextInt((max - min) + 1) + min
        TINYINT(Type.StandardType.TINYINT, (field) -> random(field, 0, Byte.MAX_VALUE - 1)),
        SMALLINT(Type.StandardType.SMALLINT, (field) -> random(field, 0, Short.MAX_VALUE - 1)),
        INTEGER(Type.StandardType.INTEGER, (field) -> random(field, 0, Integer.MAX_VALUE - 1)),
        BIGINT(Type.StandardType.BIGINT, (field) -> new Random().nextLong()),
        //Math.random() * (max - min) + min)
        FLOAT(Type.StandardType.FLOAT, (field) -> (float) Math.random() * (Float.MAX_VALUE - 1 - 0) + 0),
        DOUBLE(Type.StandardType.DOUBLE, (field) -> Math.random() * (Double.MAX_VALUE - 1 - 0) + 0),
        DATE(Type.StandardType.DATE, (field) -> dateFormat(field)),
        TIME(Type.StandardType.TIME, (field) -> dateFormat(field)),
        TIMESTAMP(Type.StandardType.TIMESTAMP, (field) -> dateFormat(field)),
        STING(Type.StandardType.VARCHAR, (field) -> randomString(field.getValidator() != null && field.getValidator().getMaxLength() != null ? field.getValidator().getMaxLength().intValue() / 2 : 5)),
        UNKNOW(Type.StandardType.NULL, (field) -> "UNKNOW");
        private Type type;
        private Function<MappedStatementMetaField, Object> function;

        TypeMock(Type type, Function<MappedStatementMetaField, Object> function) {
            this.type = type;
            this.function = function;
        }

        public Type getType() {
            return type;
        }

        public Function function() {
            return function;
        }

        @Override
        public String type() {
            return this.type.getJavaTypeAlias();
        }

        private static final String basesStringRandom = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        private static final int basesStringRandomLength = basesStringRandom.length();

        private static int random(int min, int max) {
            return new Random().nextInt((max - min) + 1) + min;
        }

        private static Object random(MappedStatementMetaField field, int min, int max) {
            if (field.getValidator() != null) {
                if (field.getValidator().getMin() != null) {
                    min = field.getValidator().getMin().intValue() > min ? field.getValidator().getMin().intValue() : min;
                }
                if (field.getValidator().getMax() != null && field.getValidator().getMax().intValue() > min) {
                    max = field.getValidator().getMax().intValue() < max ? field.getValidator().getMax().intValue() : max;
                }
                if (field.getValidator().isUnsigned()) {
                    min = min >= 0 ? min : 0;
                }
            }
            return new Random().nextInt((max - min) + 1) + min;
        }

        private static Object dateFormat(MappedStatementMetaField field) {
            if (field.getValidator() != null && StringUtils.isNotBlank(field.getValidator().getDatePattern())) {
                return DateUtil.format(new Date(), field.getValidator().getDatePattern());
            }
            return new Date();
        }


        public static String randomString(Number maxLength) {
            Random random = new Random();
            //防止特大字段长度 json、text、longtext
            maxLength = maxLength != null ? Math.min(maxLength.intValue(), Byte.MAX_VALUE) : 0;
            //指定字符串长度，拼接字符并toString
            StringBuffer stringBuffer = new StringBuffer();
            for (int i = 0; i < maxLength.intValue(); i++) {
                //获取指定长度的字符串中任意一个字符的索引值
                int number = random.nextInt(basesStringRandomLength);
                //根据索引值获取对应的字符
                char charAt = basesStringRandom.charAt(number);
                stringBuffer.append(charAt);
            }
            return stringBuffer.toString();
        }
    }


    static boolean isPrimitive(String type) {
        return typeMockMap.containsKey(type);
    }


    static Object getValue(MappedStatementMetaField field) {
        if (field != null && field.getDefaultValue() != null) {
            return field.getDefaultValue();
        }
        if (typeMockMap.containsKey(field.getType())) {
            return typeMockMap.get(field.getType()).function().apply(field);
        }
        return null;
    }

    static Object mock(MappedStatementMetaField field, CommandType commandType) {
        return mock(field, 2, commandType);
    }

    static Object mock(MappedStatementMetaField field) {
        return mock(field, 2, null);
    }

    static Object mock(MappedStatementMetaField field, int size, CommandType commandType) {
        if (field == null) {
            return null;
        }
        Object result;
        if (field.getDefaultValue() != null) {
            result = field.getDefaultValue();
        } else if (Mock.isPrimitive(field.getType())) { //基础类型
            if ((field.isAutoincrement() && commandType != CommandType.StandardCommand.INSERT && commandType != CommandType.StandardCommand.SELECT)
                    || (!field.isAutoincrement() && commandType != CommandType.StandardCommand.SELECT)
                    || (commandType == CommandType.StandardCommand.SELECT) && field.getValidator() != null && field.getValidator().isRequired()) {
                result = Mock.getValue(field);
            } else {
                result = null;
            }
        } else if (Mock.isPrimitive(field.getType()) && Type.StandardType.ARRAY.javaTypeAlias.equalsIgnoreCase(field.getGenericType())) {//数组并且泛型为基本类型
            result = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                ((List) result).add(Mock.getValue(field));
            }
        } else if (Type.StandardType.STRUCT.javaTypeAlias.equals(field.getType())) {//map
            result = new HashMap<>();
            for (MappedStatementMetaField child : field.getChildren()) {
                ((Map) result).put(child.getField(), Mock.mock(child, size, commandType));
            }
        } else if (Type.StandardType.ARRAY.javaTypeAlias.equalsIgnoreCase(field.getType()) && Type.StandardType.STRUCT.javaTypeAlias.equalsIgnoreCase(field.getGenericType())) { //数组并且泛型为map
            result = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                Map map = new HashMap();
                for (MappedStatementMetaField child : field.getChildren()) {
                    map.put(child.getField(), Mock.mock(child, size, commandType));
                }
                ((List) result).add(map);
            }
        } else {//未知类型
            result = TypeMock.UNKNOW.function.apply(field);
        }
        return result;
    }
}